﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace ASSReader
{
    public class SubtitleDocument
    {
        public ScriptInfo Info { get; private set; }
        public StyleCollection Styles { get; private set; }
        public EventCollection Events { get; private set; }

        public void Load(string Content)
        {
            using (StringReader reader = new StringReader(Content))
            {
                while (reader.Peek() >= 0)
                {
                    GetHeader(reader);
                }
            }
        }

        private void GetHeader(StringReader reader)
        {
            string StrHeader = "";
            while (!StrHeader.StartsWith("["))
            {
                StrHeader = reader.ReadLine().Trim();
            }
            switch (StrHeader)
            {
                case "[Script Info]":
                    GetScriptInfo(reader);
                    break;
                case "[V4+ Styles]":
                    GetStyles(reader);
                    break;
                case "[Events]":
                    GetEvents(reader);
                    break;
                default:
                    break;
            }
        }

        private void GetScriptInfo(StringReader reader)
        {
            string str = "";
            Info = new ScriptInfo() { };
            while (reader.Peek() != '[' && reader.Peek() >= 0)
            {
                str = reader.ReadLine().Trim();
                if (!str.StartsWith(";") && !string.IsNullOrEmpty(str))
                {
                    string[] ms = str.Split(':');
                    if (ms.Length > 1)
                    {
                        var key = ms[0];
                        var value = ms[1].Trim();
                        switch (key)
                        {
                            case "Title":
                                Info.Title = value;
                                break;
                            case "ScriptType":
                                Info.ScriptType = value;
                                break;
                            case "ScaledBorderAndShadow":
                                Info.ScaledBorderAndShadow = value.Equals("yes");
                                break;
                            case "Collisions":
                                Info.Collisions = (SubtitleCollisions)Enum.Parse(typeof(SubtitleCollisions), value, true);
                                break;
                            case "SynchPoint":
                                //Info.SynchPoint
                                break;
                            case "WrapStyle":
                                Info.WrapStyle = int.Parse(value);
                                break;
                            case "Timer":
                                Info.Timer = double.Parse(value);
                                break;
                            case "Scroll Position":
                                Info.ScrollPosition = int.Parse(value);
                                break;
                            case "Video Zoom Percent":
                                Info.VideoZoomPercent = double.Parse(value);
                                break;
                            case "PlayResX":
                                Info.PlayResX = int.Parse(value);
                                break;
                            case "PlayResY":
                                Info.PlayResY = int.Parse(value);
                                break;
                            default:
                                break;
                        }
                    }
                }
            }
        }

        private void GetStyles(StringReader reader)
        {
            string str = "";
            while (reader.Peek() != '[' && reader.Peek() >= 0)
            {
                str = reader.ReadLine().Trim();
                if (!str.StartsWith(";") && !string.IsNullOrEmpty(str))
                {
                    string[] ms = str.Split(':');
                    if (ms.Length > 1)
                    {
                        string key = ms[0];
                        string value = string.Join(":", ms, 1, ms.Length - 1);
                        if (key == "Format")
                        {
                            var Header = value.Split(',').Select(m => m.Trim());
                            Styles = new StyleCollection(Header);
                        }
                        else
                        {
                            string[] Values = value.Split(',');
                            V4Style item = new V4Style();
                            for (int i = 0; i < Values.Length; i++)
                            {
                                switch (Styles.Headers[i])
                                {
                                    case "Name":
                                        item.Name = Values[i].Trim();
                                        break;
                                    case "Fontname":
                                        item.Fontname = Values[i].Trim();
                                        break;
                                    case "Fontsize":
                                        item.Fontsize = int.Parse(Values[i].Trim());
                                        break;
                                    case "PrimaryColour":
                                        item.PrimaryColour = Values[i].Trim();
                                        break;
                                    case "SecondaryColour":
                                        item.SecondaryColour = Values[i].Trim();
                                        break;
                                    case "OutlineColour":
                                        item.OutlineColour = Values[i].Trim();
                                        break;
                                    case "BackColour":
                                        item.BackColour = Values[i].Trim();
                                        break;
                                    case "Bold":
                                        item.Bold = int.Parse(Values[i].Trim());
                                        break;
                                    case "Italic":
                                        item.Italic = int.Parse(Values[i].Trim());
                                        break;
                                    case "Underline":
                                        item.Underline = int.Parse(Values[i].Trim());
                                        break;
                                    case "StrikeOut":
                                        item.StrikeOut = int.Parse(Values[i].Trim());
                                        break;
                                    case "ScaleX":
                                        item.ScaleX = double.Parse(Values[i].Trim());
                                        break;
                                    case "ScaleY":
                                        item.ScaleY = double.Parse(Values[i].Trim());
                                        break;
                                    case "Spacing":
                                        item.Spacing = double.Parse(Values[i].Trim());
                                        break;
                                    case "Angle":
                                        item.Angle = double.Parse(Values[i].Trim());
                                        break;
                                    case "BorderStyle":
                                        item.BorderStyle = int.Parse(Values[i].Trim());
                                        break;
                                    case "Outline":
                                        item.Outline = double.Parse(Values[i].Trim());
                                        break;
                                    case "Shadow":
                                        item.Shadow = int.Parse(Values[i].Trim());
                                        break;
                                    case "Alignment":
                                        item.Alignment = int.Parse(Values[i].Trim());
                                        break;
                                    case "MarginL":
                                        item.MarginL = int.Parse(Values[i].Trim());
                                        break;
                                    case "MarginR":
                                        item.MarginR = int.Parse(Values[i].Trim());
                                        break;
                                    case "MarginV":
                                        item.MarginV = int.Parse(Values[i].Trim());
                                        break;
                                    case "Encoding":
                                        item.Encoding = int.Parse(Values[i].Trim());
                                        break;
                                    default:
                                        break;
                                }
                            }
                            Styles.Add(item);
                        }

                    }
                }
            }
        }

        private void GetEvents(StringReader reader)
        {
            string str = "";
            while (reader.Peek() != '[' && reader.Peek() >= 0)
            {
                str = reader.ReadLine().Trim();
                if (!str.StartsWith(";") && !string.IsNullOrEmpty(str))
                {
                    string[] ms = str.Split(':');
                    if (ms.Length > 1)
                    {
                        string key = ms[0].Trim();
                        string value = string.Join(":", ms, 1, ms.Length - 1);
                        if (key == "Format")
                        {
                            var Header = value.Split(',').Select(m => m.Trim());
                            Events = new EventCollection(Header);
                        }
                        else
                        {
                            Events.Add(GetEventItem(key, value));
                        }

                    }
                }
            }
        }

        public SubEvent GetEventItem(string Format, string Content)
        {
            string[] Values = Content.Split(',');
            var TextStart = Events.Headers.Count - 1;
            SubEvent item = new SubEvent() { Format = Format };
            for (int i = 0; i < Events.Headers.Count; i++)
            {
                switch (Events.Headers[i])
                {

                    case "Marked":
                        item.Marked = int.Parse(Values[i].Trim()) != 0;
                        break;
                    case "Start":
                        item.Start = TimeSpan.Parse(Values[i].Trim());
                        break;
                    case "End":
                        item.End = TimeSpan.Parse(Values[i].Trim());
                        break;
                    case "Style":
                        item.Style = Values[i].Trim();
                        break;
                    case "Name":
                        item.Name = Values[i].Trim();
                        break;
                    case "MarginL":
                        item.MarginL = int.Parse(Values[i].Trim());
                        break;
                    case "MarginR":
                        item.MarginR = int.Parse(Values[i].Trim());
                        break;
                    case "MarginV":
                        item.MarginV = int.Parse(Values[i].Trim());
                        break;
                    default:
                        break;
                }
            }
            item.Text = string.Join(",", Values, TextStart, Values.Length - TextStart);
            return item;
        }

        public SubEvent GetEventItem2(string Content)
        {
            string[] Values = Content.Split(',');
            var TextStart = Events.InnerHeaders.Count - 1;
            SubEvent item = new SubEvent() { };
            for (int i = 0; i < Events.InnerHeaders.Count; i++)
            {
                switch (Events.InnerHeaders[i])
                {
                    case "ReadOrder":
                        item.ReadOrder = int.Parse(Values[i].Trim());
                        break;
                    case "Marked":
                        item.Marked = int.Parse(Values[i].Trim()) != 0;
                        break;
                    case "Style":
                        item.Style = Values[i].Trim();
                        break;
                    case "Name":
                        item.Name = Values[i].Trim();
                        break;
                    case "MarginL":
                        item.MarginL = int.Parse(Values[i].Trim());
                        break;
                    case "MarginR":
                        item.MarginR = int.Parse(Values[i].Trim());
                        break;
                    case "MarginV":
                        item.MarginV = int.Parse(Values[i].Trim());
                        break;
                    default:
                        break;
                }
            }
            item.Text = string.Join(",", Values, TextStart, Values.Length - TextStart);
            return item;
        }


        public SubtitleDocument()
        {


        }
    }
    public class ScriptInfo
    {
        public string Title { get; set; }
        public bool ScaledBorderAndShadow { get; set; }
        public double VideoZoomPercent { get; set; }
        public int PlayResX { get; set; }
        public int PlayResY { get; set; }
        public int ScrollPosition { get; set; }
        public SubtitleCollisions Collisions { get; set; }
        public double Timer { get; set; }
        public TimeSpan SynchPoint { get; set; }
        public string ScriptType { get; set; }
        public int WrapStyle { get; set; }
    }

    public enum SubtitleCollisions
    {
        Normal,
        Reverse
    }
}
